<template>
  <transition name="viewer-fade">
    <div class="el-image-viewer__wrapper" >
      <template v-if="!isSingle">
        <span
          class="el-image-viewer__btn el-image-viewer__prev"
          :class="{ 'is-disabled': !infinite && isFirst }"
          @click="prev">
          <i class="el-icon-arrow-left"/>
        </span>
        <span
          class="el-image-viewer__btn el-image-viewer__next"
          :class="{ 'is-disabled': !infinite && isLast }"
          @click="next">
          <i class="el-icon-arrow-right"/>
        </span>
      </template>
      <div class="el-image-viewer__btn el-image-viewer__actions">
        <div class="el-image-viewer__actions__inner">
          <i class="el-icon-zoom-out" @click="handleActions('zoomOut')"></i>
          <i class="el-icon-zoom-in" @click="handleActions('zoomIn')"></i>
          <i class="el-image-viewer__actions__divider"></i>
          <i :class="mode.icon" @click="toggleMode"></i>
          <i class="el-image-viewer__actions__divider"></i>
          <i class="el-icon-refresh-left" @click="handleActions('anticlocelise')"></i>
          <i class="el-icon-refresh-right" @click="handleActions('clocelise')"></i>
        </div>
      </div>
      <div class="el-image-viewer__canvas">
        <img
          v-for="(url, i) in urlImgList"
          ref="img"
          class="el-image-viewer__img"
          :key="i"
          :src="currentImg"
          :style="imgStyle"
          @load="handleImgLoad"
          @error="handleImgError"
          @mousedown="handleMouseDown">
      </div>
    </div>
  </transition>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import { on, off } from 'element-ui/src/utils/dom'
import { rafThrottle, isFirefox } from 'element-ui/src/utils/util'
const Mode = {
  CONTAIN: {
    name: 'contain',
    icon: 'el-icon-full-screen'
  },
  ORIGINAL: {
    name: 'original',
    icon: 'el-icon-c-scale-to-original'
  }
}
const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'
@Component({
  name: 'webchatImageViewer'
})
export default class WebchatImageViewer extends Vue {
  @Prop() private urlList!: []
  @Prop({ type: Number, default: () => 2000 }) private zIndex
  @Prop(Function) public onSwitch
  @Prop(Function) public onClose
  @Prop() private domId !: ''
  @Prop() private params: any
  private index = 0

  private isShow = false

  private infinite = true

  private loading = false

  private mode = Mode.CONTAIN

  private transform = {
    scale: 1,
    deg: 0,
    offsetX: 0,
    offsetY: 0,
    enableTransition: false
  }

  private keyDownHandler: any
  private mouseWheelHandler: any
  private dragHandler: any

  get urlImgList () {
    return this.urlList.filter((item, index) => index === this.index)
  }

  get isSingle () {
    return this.urlList.length <= 1
  }

  get isFirst () {
    return this.index === 0
  }

  get isLast () {
    return this.index === this.urlList.length - 1
  }

  get currentImg () {
    return this.urlList[this.index]
  }

  get imgStyle () {
    const { scale, deg, offsetX, offsetY, enableTransition } = this.transform
    const style: any = {
      // eslint-disable-next-line quote-props
      'transform': `scale(${scale}) rotate(${deg}deg)`,
      // eslint-disable-next-line quote-props
      'transition': enableTransition ? 'transform .3s' : '',
      'margin-left': `${offsetX}px`,
      'margin-top': `${offsetY}px`
    }
    if (this.mode === Mode.CONTAIN) {
      style.maxWidth = style.maxHeight = '100%'
    }
    return style
  }

  private hide () {
    this.deviceSupportUninstall()
    this.onClose()
  }

  private deviceSupportInstall () {
    this.keyDownHandler = rafThrottle(e => {
      const keyCode = e.keyCode
      switch (keyCode) {
        // ESC
        case 27:
          this.hide()
          break
        // SPACE
        case 32:
          this.toggleMode()
          break
        // LEFT_ARROW
        case 37:
          this.prev()
          break
        // UP_ARROW
        case 38:
          this.handleActions('zoomIn')
          break
        // RIGHT_ARROW
        case 39:
          this.next()
          break
        // DOWN_ARROW
        case 40:
          this.handleActions('zoomOut')
          break
      }
    })
    this.mouseWheelHandler = rafThrottle(e => {
      const delta = e.wheelDelta ? e.wheelDelta : -e.detail
      if (delta > 0) {
        this.handleActions('zoomIn', {
          zoomRate: 0.015,
          enableTransition: false
        })
      } else {
        this.handleActions('zoomOut', {
          zoomRate: 0.015,
          enableTransition: false
        })
      }
    })
    const dom = document.getElementById(this.domId)
    // keydown事件，只能针对document对象和输入框监听
    on(document, 'keydown', this.keyDownHandler)
    on(dom, mousewheelEventName, this.mouseWheelHandler)
  }

  private deviceSupportUninstall () {
    const dom = document.getElementById(this.domId)
    off(document, 'keydown', this.keyDownHandler)
    off(dom, mousewheelEventName, this.mouseWheelHandler)
    this.keyDownHandler = null
    this.mouseWheelHandler = null
  }

  private handleImgLoad (e) {
    this.loading = false
  }

  private handleImgError (e) {
    this.loading = false
    e.target.alt = '加载失败'
  }

  private handleMouseDown (e) {
    if (this.loading || e.button !== 0) {
      return
    }
    // const bottom = (this.params.imgHeight * 0.68) + this.params.top
    const { offsetX, offsetY } = this.transform
    const startX = e.pageX
    const startY = e.pageY
    this.dragHandler = rafThrottle(ev => {
      this.transform.offsetX = offsetX + ev.pageX - startX
      this.transform.offsetY = offsetY + ev.pageY - startY
      // console.log(ev.clientY)
      // console.log(this.params.top)
      // console.log(bottom)
      // if (ev.clientY <= this.params.top || ev.clientY >= bottom) {
      //   console.log('超出')
      //   off(dom, 'mousemove', this.dragHandler)
      // }
    })
    const dom = document.getElementById(this.domId)
    on(dom, 'mousemove', this.dragHandler)
    on(dom, 'mouseup', ev => {
      off(dom, 'mousemove', this.dragHandler)
    })
    e.preventDefault()
  }

  private reset () {
    this.transform = {
      scale: 1,
      deg: 0,
      offsetX: 0,
      offsetY: 0,
      enableTransition: false
    }
  }

  private toggleMode () {
    if (this.loading) {
      return
    }
    const modeNames = Object.keys(Mode)
    const modeValues = Object.values(Mode)
    const index = modeValues.indexOf(this.mode)
    const nextIndex = (index + 1) % modeNames.length
    this.mode = Mode[modeNames[nextIndex]]
    this.reset()
  }

  private prev () {
    if (this.isFirst && !this.infinite) {
      return
    }
    const len = this.urlList.length
    this.index = (this.index - 1 + len) % len
  }

  private next () {
    if (this.isLast && !this.infinite) {
      return
    }
    const len = this.urlList.length
    this.index = (this.index + 1) % len
  }

  private handleActions (action, options = {}) {
    if (this.loading) {
      return
    }
    const { zoomRate, rotateDeg, enableTransition } = {
      zoomRate: 0.2,
      rotateDeg: 90,
      enableTransition: true,
      ...options
    }
    const { transform } = this
    switch (action) {
      case 'zoomOut':
        if (transform.scale > 0.2) {
          transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
        }
        break
      case 'zoomIn':
        transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
        break
      case 'clocelise':
        transform.deg += rotateDeg
        break
      case 'anticlocelise':
        transform.deg -= rotateDeg
        break
    }
    transform.enableTransition = enableTransition
  }

  private mounted () {
    this.deviceSupportInstall()
  }

  @Watch('index')
  private indexChange (val) {
    this.reset()
    // this.onSwitch(val)
  }

  @Watch('currentImg')
  private currentImgChange (val) {
    this.$nextTick(() => {
      const $img = this.$refs.img[0]
      if (!$img.complete) {
        this.loading = true
      }
    })
  }
}
</script>
<style lang="stylus" scoped>
.el-image-viewer__wrapper
  position static
  overflow hidden
  height 100%
  width 100%
</style>
